package com.szly.phm.common.utils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class DateUtils {
    public static Date defaultDateTime;



    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class DateRange {
        private Date begin;
        private Date end;
    }

    public enum TenDayType {
        上,
        中,
        下,
    }

    static {
        try {
            defaultDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("1900-01-01 00:00:00");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取年的第一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getYearFistDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.set(c.get(Calendar.YEAR), Calendar.JANUARY, 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取年的最后一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getYearLastDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(getYearFistDateTime(date));
        c.add(Calendar.YEAR, 1);
        c.set(Calendar.MILLISECOND, -1);
        return c.getTime();
    }

    /**
     * 获取月的第一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getMonthFistDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH), 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取月的最后一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getMonthLastDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(getMonthFistDateTime(date));
        c.add(Calendar.MONTH, 1);
        c.add(Calendar.MILLISECOND, -1);
        return c.getTime();
    }


    /**
     * 获取周的第一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getWeekFistDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //中国第一周是周一,安信科创项目不考虑全球化.
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.setTime(date);
        c.set(Calendar.DATE, c.get(Calendar.DATE) - c.get(Calendar.DAY_OF_WEEK) + (c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY ? -5 : 2));
        return c.getTime();
    }

    /**
     * 获取周的最后一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getWeekLastDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(getWeekFistDateTime(date));
        c.add(Calendar.DATE, 7);
        c.add(Calendar.MILLISECOND, -1);
        return c.getTime();
    }

    /**
     * 获取日的第一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getDayFistDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(getDate(date));
        return c.getTime();
    }

    /**
     * 获取日的最后一个时刻.
     *
     * @param date 传入日期.
     * @return a Date.
     */
    public static Date getDayLastDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(getDayFistDateTime(date));
        c.add(Calendar.DATE, 1);
        c.add(Calendar.MILLISECOND, -1);
        return c.getTime();
    }

    /**
     * @description: 获取指定旬日期范围
     *
     * @author hdj
     * @date 2020/9/28 10:51
     */
    public static DateRange getTenDayRange(int year, int month, TenDayType type) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        switch (type) {
            case 上:
                c.set(Calendar.DAY_OF_MONTH, 1);
                return new DateRange(getTenDayFirstDateTime(c.getTime()), getTenDayLastDateTime(c.getTime()));
            case 中:
                c.set(Calendar.DAY_OF_MONTH, 11);
                return new DateRange(getTenDayFirstDateTime(c.getTime()), getTenDayLastDateTime(c.getTime()));
            default:
                c.set(Calendar.DAY_OF_MONTH, 21);
                return new DateRange(getTenDayFirstDateTime(c.getTime()), getTenDayLastDateTime(c.getTime()));
        }
    }

    /**
     * @description: 获取当前旬的日期范围
     *
     * @author hdj
     * @date 2020/9/28 10:51
     */
    public static DateRange getTenDayRange(Date date) {
        return new DateRange(getTenDayFirstDateTime(date), getTenDayLastDateTime(date));
    }


    /**
     * @description: 获取下一个旬的日期范围
     *
     * @author hdj
     * @date 2020/9/28 10:51
     */
    public static DateRange getNextTenDayRange(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        if (c.get(Calendar.DAY_OF_MONTH) >= 21) {
            c.set(Calendar.DAY_OF_MONTH, 1);
            c.add(Calendar.MONTH, 1);
            c.add(Calendar.DAY_OF_MONTH, -1);
        } else if (c.get(Calendar.DAY_OF_MONTH) >= 11) {
            c.set(Calendar.DAY_OF_MONTH, 21);
        } else {
            c.set(Calendar.DAY_OF_MONTH, 1);
        }

        return getTenDayRange(c.getTime());
    }

    /**
     * @description: 获取上一个旬的日期范围
     *
     * @author hdj
     * @date 2020/9/28 10:51
     */
    public static DateRange getPrevTenDayRange(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        if (c.get(Calendar.DAY_OF_MONTH) >= 21) {
            c.set(Calendar.DAY_OF_MONTH, 11);
        } else if (c.get(Calendar.DAY_OF_MONTH) >= 11) {
            c.set(Calendar.DAY_OF_MONTH, 1);
        } else {
            c.set(Calendar.DAY_OF_MONTH, 1);
            c.add(Calendar.DAY_OF_MONTH, -1);
        }

        return getTenDayRange(c.getTime());
    }

    /**
     * @description: 获取当前时间的旬起始时间
     * @author hdj
     * @date 2020/9/28 10:29
     */
    public static Date getTenDayFirstDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(clearTime(date));
        var first = 1;
        if (c.get(Calendar.DAY_OF_MONTH) >= 21) {
            first = 21;
        } else if (c.get(Calendar.DAY_OF_MONTH) >= 11) {
            first = 11;
        } else {
            first = 1;
        }

        c.set(Calendar.DAY_OF_MONTH, first);
        return getDate(c.getTime());
    }

    /**
     * @description: 获取当前时间的旬结束时间
     * @author hdj
     * @date 2020/9/28 10:29
     */
    public static Date getTenDayLastDateTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(clearTime(date));
        if (c.get(Calendar.DAY_OF_MONTH) >= 21) {
            c.set(Calendar.DAY_OF_MONTH, 1);
            c.add(Calendar.MONTH, 1);
        } else if (c.get(Calendar.DAY_OF_MONTH) >= 11) {
            c.set(Calendar.DAY_OF_MONTH, 21);
        } else {
            c.set(Calendar.DAY_OF_MONTH, 11);
        }
        c.add(Calendar.MILLISECOND, -1);
        return c.getTime();
    }

    /**
     * 时间段相差的天数
     * @author chengjiang
     * @date 2020/9/29
     */
    public static int daysBetween(Date small,Date big) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        try {
            small=sdf.parse(sdf.format(small));
            big=sdf.parse(sdf.format(big));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        cal.setTime(small);
        long time1 = cal.getTimeInMillis();
        cal.setTime(big);
        long time2 = cal.getTimeInMillis();
        long between_days=(time2-time1)/(1000*3600*24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 获取结束时间（23:59:59）
     * @author chengjiang
     * @date 2020/10/16
     */
    public static Date getEndDate(Date date) {
        date = clearTime(date);
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.DATE,1);
        c.set(Calendar.MILLISECOND, -1);
        return c.getTime();
    }

    /**
     * 获取 Date 日期部分
     *
     * @param date 传入日期.
     * @return a Date 时间部分为 00:00:00.
     */
    public static Date getDate(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }
    /**
     * 获取 Date 日期部分
     *
     * @param date 传入日期.
     * @return a Date 时间部分为 00:00:00.
     */
    public static Date clearTime(Date date) {
        return getDate(date);
    }

    /**
     * 是否大于 标定日期
     *
     * @param date        日期.
     * @param compareDate 标定日期.
     * @return a boolean.
     */
    public static boolean isAfter(Date date, Date compareDate) {
        return isAfter(date, compareDate, false);
    }

    /**
     * 是否大于(是否含边界值) 标定日期
     *
     * @param date              日期.
     * @param compareDate       标定日期.
     * @param isIncludeBoundary 是否包含边界值.
     * @return a boolean.
     */
    public static boolean isAfter(Date date, Date compareDate, boolean isIncludeBoundary) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        var cc = Calendar.getInstance();
        cc.setTime(compareDate);

        return isIncludeBoundary ? c.compareTo(cc) >= 0 : c.compareTo(cc) > 0;
    }

    /**
     * 是否小于 标定日期
     *
     * @param date        日期.
     * @param compareDate 标定日期.
     * @return a boolean.
     */
    public static boolean isBefore(Date date, Date compareDate) {
        return isBefore(date, compareDate, false);
    }

    /**
     * 是否小于(是否含边界值) 标定日期
     *
     * @param date              日期.
     * @param compareDate       标定日期.
     * @param isIncludeBoundary 是否包含边界值.
     * @return a boolean.
     */
    public static boolean isBefore(Date date, Date compareDate, boolean isIncludeBoundary) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        var cc = Calendar.getInstance();
        cc.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        cc.setTime(compareDate);

        return isIncludeBoundary ? c.compareTo(cc) <= 0 : c.compareTo(cc) < 0;
    }

    /**
     * 是否在区间范围内,包含边界
     *
     * @param date      日期.
     * @param beginDate 开始日期.
     * @param endDate   结束日期.
     * @return a boolean.
     */
    public static boolean isBetween(Date date, Date beginDate, Date endDate) {
        return isBetween(date, beginDate, endDate, true);
    }

    /**
     * 是否不在区间范围内,包含边界
     *
     * @param date      日期.
     * @param beginDate 开始日期.
     * @param endDate   结束日期.
     * @return a boolean.
     */
    public static boolean isNotBetween(Date date, Date beginDate, Date endDate) {
        return !isBetween(date, beginDate, endDate);
    }

    /**
     * 是否在区间范围内
     *
     * @param date              日期.
     * @param beginDate         开始日期.
     * @param endDate           结束日期.
     * @param isIncludeBoundary 是否包含边界.
     * @return a boolean.
     */
    public static boolean isBetween(Date date, Date beginDate, Date endDate, boolean isIncludeBoundary) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        var bc = Calendar.getInstance();
        bc.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        bc.setTime(beginDate);
        var ec = Calendar.getInstance();
        ec.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        ec.setTime(endDate);
        return isIncludeBoundary
                ? c.compareTo(bc) >= 0 && c.compareTo(ec) <= 0
                : c.compareTo(bc) > 0 && c.compareTo(ec) < 0;
    }

    /**
     * 是否不在区间范围(是否包含边界值)内
     *
     * @param date              日期.
     * @param beginDate         开始日期.
     * @param endDate           结束日期.
     * @param isIncludeBoundary 是否包含边界.
     * @return a boolean.
     */
    public static boolean isNotBetween(Date date, Date beginDate, Date endDate, boolean isIncludeBoundary) {
        return !isBetween(date, beginDate, endDate, isIncludeBoundary);
    }

    /**
     * 添加月
     *
     * @param date
     * @param month
     * @return
     */
    public static Date addMonth(Date date, int month) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.MONTH, month);
        return c.getTime();
    }

    /**
     * 添加日
     *
     * @param date
     * @param day
     * @return
     */
    public static Date addDay(Date date, int day) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.DATE, day);
        return c.getTime();
    }

    /**
     * 添加年
     *
     * @param date
     * @param year
     * @return
     */
    public static Date addYear(Date date, int year) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.YEAR, year);
        return c.getTime();
    }

    /**
     * 添加小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date addHour(Date date, int hour) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.HOUR, hour);
        return c.getTime();
    }

    /**
     * 添加分钟
     *
     * @param date
     * @param minute
     * @return
     */
    public static Date addMinute(Date date, int minute) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.MINUTE, minute);
        return c.getTime();
    }

    /**
     * 添加秒
     *
     * @param date
     * @param second
     * @return
     */
    public static Date addSecond(Date date, int second) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.SECOND, second);
        return c.getTime();
    }

    /**
     * 添加毫秒
     *
     * @param date
     * @param millisecond
     * @return
     */
    public static Date addMilliSecond(Date date, int millisecond) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.add(Calendar.MILLISECOND, millisecond);
        return c.getTime();
    }

    /**
     * 是否是周末
     *
     * @param date
     * @return
     */
    public static boolean isWeekend(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        return c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY;
    }

    /**
     * 是否是闰年.
     *
     * @param date
     * @return
     */
    public static boolean isLeapYear(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        return c.get(Calendar.YEAR) % 4 == 0;
    }

    /**
     * 格式化输出
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 格式化输出为 yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String format(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }


    /**
     * 格式化输出
     *
     * @param timestamp
     * @param pattern
     * @return
     */
    public static String format(Timestamp timestamp, String pattern) {
        return format(convertToDate(timestamp), pattern);
    }

    /**
     * 转换timestamp到Date
     *
     * @param timestamp
     * @return
     */
    public static Date convertToDate(Timestamp timestamp) {
        return new Date(timestamp.getTime());
    }

    /**
     * 转换timestamp到SQL Date
     *
     * @param timestamp
     * @return
     */
    public static java.sql.Date convertToSQLDate(Timestamp timestamp) {
        return new java.sql.Date(timestamp.getTime());
    }


    /**
     * 转换Date到timestamp
     *
     * @param date
     * @return
     */
    public static Timestamp convertToTimestamp(Date date) {
        return new Timestamp(date.getTime());
    }


    /**
     * 转换Date到SQL timestamp
     *
     * @param date
     * @return
     */
    public static Timestamp convertToSQLTimestamp(Date date) {
        return new Timestamp(date.getTime());
    }

    /**
     * 转换时区
     * @author chengjiang
     * @date 2021/4/26
     */
    public static Date changeTimeZone(Date date) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
        calendar.setTime(date);
        return calendar.getTime();
    }

    /**
     * 获取当前月的天数
     * @author chengjiang
     * @date 2021/4/27
     */
    public static int getDayByCurrentMonth(){
        var calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        return calendar.getActualMaximum(Calendar.DATE);
    }

    public static Date getHourFirstTime(Date date) {
        var c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        c.setTime(date);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**和最后一天
     *
     * @param date 指定日期
     * @param pattern 日期格式
     * @return
     */
    public static String getFirstDayByQuarter(Date date, String pattern) {
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        Date theDate = calendar.getTime();
        // 第一天
        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, 1);
        String day_first = df.format(gcLast.getTime());
        // 最后一天
        return day_first;
    }
    /**
     * 某一个月第一天和最后一天
     *
     * @param date 指定日期
     * @param pattern 日期格式
     * @return
     */
    public static String getLastDayByQuarter(Date date,String pattern) {
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        Calendar calendar = Calendar.getInstance();

        calendar.setTime(date);
        // 最后一天
        calendar.add(Calendar.MONTH, 1); // 加一个月
        calendar.set(Calendar.DATE, 1); // 设置为该月第一天
        calendar.add(Calendar.DATE, -1); // 再减一天即为上个月最后一天
        String day_last = df.format(calendar.getTime());
        return day_last;
    }
}
